#include "udpthread.h"

#include <QMutexLocker>
#include <QDateTime>

#pragma region worker类，维护通信
MyUdpThreadWorker::MyUdpThreadWorker(QObject* parent)
    : QObject(parent)
    , m_udpSocket(nullptr)
    , m_netWorkDatagram(new QNetworkDatagram())
    , m_isConnected(false)
{
}

MyUdpThreadWorker::~MyUdpThreadWorker()
{
}

void MyUdpThreadWorker::Slot_setLocalPort(short port)
{
    m_localPort = port;
}

void MyUdpThreadWorker::Slot_setDestinationIpPort(const QString& ip,  short port)
{
    m_destinationIp = ip;
    m_destinationPort = port;
    m_netWorkDatagram->setDestination(QHostAddress(ip), port);
}

void MyUdpThreadWorker::Slot_Connect()
{   
    QMutexLocker locker(&m_mutex);

    if(m_isConnected){
        return;
    }
    m_udpSocket.reset(new QUdpSocket());
    bool res = m_udpSocket->bind(QHostAddress::Any, m_localPort);
    qDebug()<<"bind"<<m_localPort;
    if(res){
        m_isConnected = true;
        connect(m_udpSocket.data(), &QUdpSocket::readyRead, this, [=](){
            while(m_udpSocket->hasPendingDatagrams()){
                QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
                emit Sig_receive(datagram.data());
                qDebug()<<QDateTime::currentDateTime().toString()<<"recv:"<<datagram.data();
            }
        });
    }else{
        emit Sig_error(QString("绑定端口失败，%1").arg(m_udpSocket->errorString()));
    }
    m_waitCondition.notify_all();
}

void MyUdpThreadWorker::Slot_DisConnect()
{   
    
    QMutexLocker locker(&m_mutex);
    if(!m_isConnected){
        
        
    }else{
        
        m_udpSocket->close();
        m_udpSocket.reset(nullptr);
        m_isConnected = false;
    }
    
    m_waitCondition.notify_all();
}

int MyUdpThreadWorker::Slot_Send(QByteArray data)
{
    int64_t res = -1;
    
    m_netWorkDatagram->setData(data);
    if(!m_udpSocket.isNull() && m_udpSocket->isValid()){
        res = m_udpSocket->writeDatagram(*m_netWorkDatagram.data());
        if(res != data.size()){
            emit Sig_error(QString("发送数据失败，%1").arg(m_udpSocket->errorString()));
        }else{
            qDebug()<<QDateTime::currentDateTime().toString()<<"send success";
        }
        m_udpSocket->flush(); 
    }
    return res;
}
#pragma endregion
 
 
 UdpThread::UdpThread(QObject* parent)
    :m_worker(nullptr)
    ,m_workThread(nullptr)
 {
    this->startThread();
 }
 UdpThread::~UdpThread()
{
    this->stopThread();
}

bool UdpThread::startThread()
{
    
    if(m_workThread != nullptr && m_workThread->isRunning()){
        return false;
    }
    
    m_worker = new MyUdpThreadWorker();
    m_workThread = new QThread();
    m_worker->moveToThread(m_workThread);
    
    connect(m_workThread, &QThread::finished, m_workThread, &QThread::deleteLater);
    //读+写+错误+连接+断开+设置信号
    connect(m_worker, &MyUdpThreadWorker::Sig_receive, this, &UdpThread::Sig_receive);
    connect(m_worker, &MyUdpThreadWorker::Sig_error, this, &UdpThread::Sig_errorCur);
    connect(this, &UdpThread::Sig_send, m_worker, &MyUdpThreadWorker::Slot_Send);
    connect(this, &UdpThread::sig_connect, m_worker, &MyUdpThreadWorker::Slot_Connect);
    connect(this, &UdpThread::Sig_disConnect, m_worker, &MyUdpThreadWorker::Slot_DisConnect);
    
    connect(this, &UdpThread::Sig_setLocalPort, m_worker, &MyUdpThreadWorker::Slot_setLocalPort);
    connect(this, &UdpThread::Sig_setDestinationIpPort, m_worker, &MyUdpThreadWorker::Slot_setDestinationIpPort);

    m_workThread->start();
    
    return true;
}
bool UdpThread::stopThread()
{
    if(m_workThread!= nullptr && m_workThread->isRunning()){
        m_workThread->quit();
        m_workThread->wait();
        return true;
    }
    return false;
}

void UdpThread::SetLocalPort(short port)
{
    emit Sig_setLocalPort(port);
}
void UdpThread::SetDestinationIpPort(const QString& destinationIp,  short port)
{
    emit Sig_setDestinationIpPort(destinationIp, port);
}
bool UdpThread::Connect()
{
    QMutexLocker locker(&m_worker->m_mutex);
    emit sig_connect();
    m_worker->m_waitCondition.wait(&m_worker->m_mutex);
    
    return m_worker->m_isConnected;
}
bool UdpThread::DisConnect()
{
    
    QMutexLocker locker(&m_worker->m_mutex);
    
    emit Sig_disConnect();
    
    m_worker->m_waitCondition.wait(&m_worker->m_mutex);
    
    return !m_worker->m_isConnected;
}
int UdpThread::SendData(QByteArray data)
{
    emit Sig_send(data);
}